'''
实验名称：模拟I2C控制OLED显示
版本：v1.0
作者：根据需求改写
实验平台：01Studio CanMV K230
教程：wiki.01studio.cc
'''

from machine import Pin
from machine import FPIOA
import time
#SCL_PIN = 87
#SDA_PIN = 89
# 假设 SCL 接 pin87，SDA 接 pin89
fpioa = FPIOA()
fpioa.set_function(62,FPIOA.GPIO62)
fpioa.set_function(63,FPIOA.GPIO63)

OLED_ADDR = 0x78  # OLED 的 I2C 地址

# 初始化引脚
scl = Pin(62, Pin.OUT)
sda = Pin(63, Pin.OUT)

# OLED 字模库，宽 8 像素，高 16 像素
OLED_F8x16 = [
    # 空格到 ~ 的ASCII字符集 (32-126)
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 32: ' '
    [0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00],  # 33: '!'
    [0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 34: '"'
    [0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00],  # 35: '#'
    [0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00],  # 36: '$'
    [0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00],  # 37: '%'
    [0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10],  # 38: '&'
    [0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 39: '''
    [0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00],  # 40: '('
    [0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00],  # 41: ')'
    [0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00],  # 42: '*'
    [0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00],  # 43: '+'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00],  # 44: ','
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00],  # 45: '-'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00],  # 46: '.'
    [0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x00,0x00,0x00,0x01,0x0E,0x30,0x40],  # 47: '/'
    [0x00,0x70,0x88,0x88,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 48: '0'
    [0x00,0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 49: '1'
    [0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 50: '2'
    [0x00,0x18,0x28,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 51: '3'
    [0x00,0x00,0x08,0x38,0x48,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 52: '4'
    [0x00,0x00,0xF8,0x08,0x08,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 53: '5'
    [0x00,0x70,0x88,0x08,0x08,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 54: '6'
    [0x00,0x00,0x08,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 55: '7'
    [0x00,0x30,0x48,0x08,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 56: '8'
    [0x00,0x30,0x48,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 57: '9'
    [0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00],  # 58: ':'
    [0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x03,0x00,0x00,0x00],  # 59: ';'
    [0x00,0x00,0x00,0x08,0x18,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 60: '<'
    [0x00,0x00,0x00,0x78,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 61: '='
    [0x00,0x00,0x00,0x40,0x20,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 62: '>'
    [0x00,0x00,0x30,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 63: '?'
    [0x00,0x70,0x88,0xEC,0x90,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 64: '@'
    [0x00,0x00,0x08,0xF8,0x48,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 65: 'A'
    [0x00,0xF0,0x88,0x88,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 66: 'B'
    [0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 67: 'C'
    [0x00,0xF0,0x48,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 68: 'D'
    [0x00,0xF0,0x48,0x48,0x48,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 69: 'E'
    [0x00,0xF0,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 70: 'F'
    [0x00,0x30,0x48,0x48,0x48,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 71: 'G'
    [0x00,0xF0,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 72: 'H'
    [0x00,0x00,0x48,0xF8,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 73: 'I'
    [0x00,0x20,0x40,0x48,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 74: 'J'
    [0x00,0xF0,0x08,0x10,0x20,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 75: 'K'
    [0x00,0xF0,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 76: 'L'
    [0x00,0xF0,0x02,0x0C,0x02,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 77: 'M'
    [0x00,0xF0,0x04,0x08,0x10,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 78: 'N'
    [0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 79: 'O'
    [0x00,0xF0,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 80: 'P'
    [0x00,0x30,0x48,0x48,0x58,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 81: 'Q'
    [0x00,0xF0,0x08,0x18,0x28,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 82: 'R'
    [0x00,0x00,0x70,0x88,0x08,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 83: 'S'
    [0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 84: 'T'
    [0x00,0xE0,0x10,0x10,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 85: 'U'
    [0x00,0x70,0x28,0x10,0x28,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 86: 'V'
    [0x00,0xF0,0x20,0x10,0x20,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 87: 'W'
    [0x00,0x60,0x10,0x08,0x10,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 88: 'X'
    [0x00,0x08,0x08,0x70,0x88,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 89: 'Y'
    [0x00,0x00,0x10,0x38,0x60,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 90: 'Z'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 91: '['
    [0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 92: '\'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 93: ']'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 94: '^'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 95: '_'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 96: '`'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 97: 'a'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 98: 'b'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 99: 'c'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 100: 'd'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 101: 'e'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 102: 'f'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 103: 'g'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 104: 'h'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 105: 'i'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 106: 'j'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 107: 'k'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 108: 'l'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 109: 'm'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 110: 'n'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 111: 'o'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 112: 'p'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 113: 'q'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 114: 'r'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 115: 's'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 116: 't'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 117: 'u'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 118: 'v'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 119: 'w'
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],  # 120: 'x'
]
# 模拟 I2C 起始信号
def i2c_start():
    sda.value(1)
    scl.value(1)
    sda.value(0)
    scl.value(0)

# 模拟 I2C 停止信号
def i2c_stop():
    sda.value(0)
    scl.value(1)
    sda.value(1)

# 模拟 I2C 发送一个字节
def i2c_send_byte(byte):
    for i in range(8):
        sda.value((byte >> (7 - i)) & 0x01)
        scl.value(1)
        scl.value(0)
    scl.value(1)  # 额外的一个时钟，不处理应答信号
    scl.value(0)

# OLED 写命令
def oled_write_command(command):
    i2c_start()
    i2c_send_byte(OLED_ADDR)  # 从机地址
    i2c_send_byte(0x00)  # 写命令
    i2c_send_byte(command)
    i2c_stop()

# OLED 写数据
def oled_write_data(data):
    i2c_start()
    i2c_send_byte(OLED_ADDR)  # 从机地址
    i2c_send_byte(0x40)  # 写数据
    i2c_send_byte(data)
    i2c_stop()

# OLED 初始化
def oled_init():
    time.sleep(1)  # 上电延时

    oled_write_command(0xAE)  # 关闭显示
    oled_write_command(0xD5)  # 设置显示时钟分频比/振荡器频率
    oled_write_command(0x80)
    oled_write_command(0xA8)  # 设置多路复用率
    oled_write_command(0x3F)
    oled_write_command(0xD3)  # 设置显示偏移
    oled_write_command(0x00)
    oled_write_command(0x40)  # 设置显示起始行
    oled_write_command(0xA1)  # 设置左右方向：0xA1 正常 0xA0 左右反置
    oled_write_command(0xC8)  # 设置上下方向：0xC8 正常 0xC0 上下反置
    oled_write_command(0xDA)  # 设置 COM 引脚硬件配置
    oled_write_command(0x12)
    oled_write_command(0x81)  # 设置对比度控制
    oled_write_command(0xCF)
    oled_write_command(0xD9)  # 设置预充电周期
    oled_write_command(0xF1)
    oled_write_command(0xDB)  # 设置 VCOMH 取消选择级别
    oled_write_command(0x30)
    oled_write_command(0xA4)  # 设置整个显示打开/关闭
    oled_write_command(0xA6)  # 设置正常/倒转显示
    oled_write_command(0x8D)  # 设置充电泵
    oled_write_command(0x14)
    oled_write_command(0xAF)  # 开启显示

    oled_clear()  # OLED 清屏

# OLED 清屏
def oled_clear():
    for j in range(8):
        oled_set_cursor(j, 0)
        for i in range(128):
            oled_write_data(0x00)

# OLED 设置光标位置
def oled_set_cursor(y, x):
    oled_write_command(0xB0 | y)  # 设置 Y 位置
    oled_write_command(0x10 | ((x & 0xF0) >> 4))  # 设置 X 位置高 4 位
    oled_write_command(0x00 | (x & 0x0F))  # 设置 X 位置低 4 位

# OLED 显示一个字符
def oled_show_char(line, column, char):
    ascii_offset = ord(char) - ord(' ')
    oled_set_cursor((line - 1) * 2, (column - 1) * 8)
    for i in range(8):
        oled_write_data(OLED_F8x16[ascii_offset][i])
    oled_set_cursor((line - 1) * 2 + 1, (column - 1) * 8)
    for i in range(8):
        oled_write_data(OLED_F8x16[ascii_offset][i + 8])

# OLED 显示字符串
def oled_show_string(line, column, string):
    for i, char in enumerate(string):
        oled_show_char(line, column + i, char)

# 初始化 OLED
oled_init()

# 显示字符
oled_show_char(1, 1, '1')

# 显示字符串
oled_show_string(2, 1, "012345678")